#include <allegro5/allegro.h>
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_ttf.h>

#include <vector>
#include <boost/smart_ptr.hpp>
using boost::scoped_ptr;
using boost::shared_ptr;

using namespace std;

#include "Globals.h"

#include "Display.h"
#include "BitmapDraw.h"
#include "Input.h"

#include "GameElement.h"
#include "LifeForm.h"
#include "Man.h"
#include "Monster.h"
#include "Soil.h"
#include "Arrow.h"

#include "Render.h"

vector<shared_ptr<Monster > > monsters;
vector<shared_ptr<Monster > >::iterator iter;

void next_level(shared_ptr<Man > DigDug, shared_ptr<Soil > soil, int monster_number);

int main(int argc, char **argv)
{

    enum GAME_STATE
    {
        TITLE,
        PLAYING=1,
        LEVEL_PASS,
        GAME_OVER
    };

    bool finish = false;
    bool render = false;
    int game_state = TITLE;
    int monster_numb = 2;
    int current_monster_numb = monster_numb;

    shared_ptr<Display > display ( new Display() );

    shared_ptr<BitmapDraw > bitmap_draw ( new BitmapDraw(display->get_font18(),
                                            display->get_font36(),
                                            display->get_font144()) );
    bitmap_draw->DrawAllBitmaps();

    shared_ptr<Input > input( new Input(display->get_event_queue()) );

    shared_ptr<Man > dig_dug ( new Man() );
    dig_dug -> initialise();

    shared_ptr<Soil > soil ( new Soil(dig_dug) );
    soil -> initialise();

    shared_ptr<Arrow > arrow ( new Arrow(dig_dug) );
    arrow -> initialise();

    shared_ptr<Render > game_render ( new Render(bitmap_draw, display->get_display()) );
    game_render -> initialise();

    next_level( dig_dug, soil, monster_numb );

    display->start_timer();

    while(!finish)
    {
        input->wait_for_event();
        input->key_press(finish);

        //update
        if (input->get_ev().type == ALLEGRO_EVENT_TIMER )
        {
            if (game_state == PLAYING)
            {

                if (input->get_key(UP)) dig_dug -> move_up();
                else if (input->get_key(DOWN)) dig_dug -> move_down();
                else dig_dug -> still_y();

                if (input->get_key(LEFT)) dig_dug -> move_left();
                else if (input->get_key(RIGHT)) dig_dug -> move_right();
                else dig_dug -> still_x();

                dig_dug -> update();
                soil -> update();

                if(input->get_key(SPACE)) arrow -> set_expand();
                arrow -> update();

                for ( iter = monsters.begin(); iter != monsters.end(); iter++ )
                {
                    (*iter)-> update();
                }

                //collisions
                for ( iter = monsters.begin(); iter != monsters.end(); iter++  )
                {
                    //collisions with arrow head
                    if ( arrow->check_collision( (*iter)->get_pos_x(), (*iter)->get_pos_y() ) )
                        (*iter)->set_alive(false);

                    //collisions with dig dug
                    if  ( dig_dug->check_collision( (*iter)->get_pos_x(), (*iter)->get_pos_y() ) )
                        dig_dug->lose_life();
                        //al_rest(0.1);
                }

                //destroy the dead
                for ( iter = monsters.begin(); iter != monsters.end();  )
                {
                    if ( !(*iter)->get_alive() )
                    {
                        (*iter).reset();
                        iter = monsters.erase(iter);
                        dig_dug -> score_point();
                        current_monster_numb --;
                    }
                    else iter++;
                }

                //if  no monsters remaining level passed
                if ( monsters.size() == 0 )
                    game_state = LEVEL_PASS;

                //check life of dig dug
                if ( !dig_dug->get_alive() )
                    game_state = GAME_OVER;
            }

            else if ( game_state == LEVEL_PASS )
            {
                if (input->get_key(SPACE))  //wait for user to press space
                {
                    soil -> initialise();
                    dig_dug -> initialise();
                    bitmap_draw -> reinit_SoilImage();
                    game_render -> initialise();
                    monster_numb += 1;
                    current_monster_numb = monster_numb;
                    next_level( dig_dug, soil, monster_numb );
                    game_state = PLAYING;
                }
            }

            else if ( game_state == GAME_OVER )
            {
                if (input->get_key(SPACE))  //wait for user to press space
                {
                    soil -> initialise();
                    dig_dug -> initialise();
                    bitmap_draw -> reinit_SoilImage();
                    game_render -> initialise();
                    next_level( dig_dug, soil, monster_numb );
                    game_state = PLAYING;
                }
            }

            else if ( game_state == TITLE )
            {
                if (input->get_key(SPACE))  //wait for user to press space
                {
                   game_state = PLAYING;
                }
            }

            render = true;
        }

        //render
        if (render && al_is_event_queue_empty(display->get_event_queue()))  //try change here<<<
        {
            render = false;

            if( game_state == PLAYING )
            {
                game_render -> render_Soil();
                game_render -> render_Man(dig_dug);
                game_render -> render_Arrow(arrow);

                for ( iter = monsters.begin(); iter != monsters.end(); iter++ )
                {
                    game_render->render_Monster( (*iter)->get_face_direction(), (*iter)->get_pos_x(), (*iter)->get_pos_y(), (*iter)->get_disembody()  );
                }

                al_draw_textf(display->get_font36(), al_map_rgb(255, 255, 255), 5, 5, 0, "Lives: %i", dig_dug->get_lives()-1);
                al_draw_textf(display->get_font36(), al_map_rgb(255, 255, 255), 5, 50, 0, "Points: %i", dig_dug->get_score());
                al_draw_textf(display->get_font36(), al_map_rgb(255, 255, 255), 1100, 5, 0, "Level: %i", monster_numb-1);
                al_draw_textf(display->get_font36(), al_map_rgb(255, 255, 255), 1100, 50, 0, "Monsters: %i", current_monster_numb);

                al_set_target_backbuffer(display->get_display());
                al_hold_bitmap_drawing(true);
                al_draw_bitmap(bitmap_draw->get_MainImage(), 0, 0, 0);
                al_hold_bitmap_drawing(false);
            }

            else if ( game_state == LEVEL_PASS ) game_render -> render_LevelPass();

            else if ( game_state == GAME_OVER ) game_render -> render_GameOver();

            else if ( game_state == TITLE ) game_render -> render_Title();

            display->update();
        }

        if (input->get_ev().type == ALLEGRO_EVENT_DISPLAY_CLOSE ) finish = true;

    }

    return 0;
}

void next_level(shared_ptr<Man > DigDug, shared_ptr<Soil > soil, int monster_number)
{
    monsters.clear();

    for ( int i = 0; i < monster_number; i++ )
    {
        shared_ptr<Monster > monster ( new Monster(DigDug, soil) );
        monsters.push_back(monster);
    }

    for ( iter = monsters.begin(); iter != monsters.end(); iter++ )
    {
        (*iter)->initialise();
    }
}
